﻿using CsvHelper;
using CsvHelper.Configuration.Attributes;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIA.Integration.Domain.Production;
using VIA.Integration.Domain;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using VIA.SiMoJi.Domain.Electronics;
using VIA.SiMoJi.Domain.Vision;

namespace VIA.SiMoJi.Domain
{
    public interface IDataStorageService
    {
        ConcurrentDictionary<int, double> LiJuDictionaries { get; set; }
        void SaveDataCsv(TrayPointStatus[] trayPointStatuses);
        void SaveDataCsv(CalcTimeOption calcOption);
    }

    public class DataStorageService : IDataStorageService
    {
        readonly IOptionRepository _optionRepository;
        readonly IProductionLine _productionLine;
        readonly ILogger _logger;
        readonly IShiftService _shiftService;
        readonly ICurrentRecipe _currentRecipe;
        public ConcurrentDictionary<int, double> LiJuDictionaries { get; set; } = new ConcurrentDictionary<int, double>();
        public DataStorageService(IServiceProvider service)
        {
            _logger = service.GetRequiredService<ILogger<DataStorageService>>();
            _optionRepository = service.GetService<IOptionRepository>();
            _productionLine = service.GetService<IProductionLine>();
            _shiftService = service.GetService<IShiftService>();
            _currentRecipe = service.GetService<ICurrentRecipe>();
        }
        public void SaveDataCsv(TrayPointStatus[] trayPointStatuses)
        {
            var option = _optionRepository.Get<DataStorageOption>();
            if (option.IsSaveCSV == false) return;
            DateTime createTime = DateTime.Now;
            if (_shiftService.Current == Shift.Night)
            {
                createTime = createTime.AddHours(-12);
            }
            var dateStr = createTime.ToString("yyyy-MM-dd");
            string csvPath = Path.Combine(option.CSVPath, dateStr);
            EnsureExist(csvPath);
            string filePath = Path.Combine(csvPath, $"{dateStr}-产品记录.csv");
            var _barcodeDictionary = _productionLine.BarcodeDictionaries;
            for (int i = 0; i < trayPointStatuses.Count(); i++)
            {
                var trayPointStatus = trayPointStatuses[i];
                int jawNumber = i + 1;
                if (trayPointStatus != TrayPointStatus.Empty)
                {
                    string barcode = string.Empty;
                    double liJuValue = 0;
                    _barcodeDictionary.TryGetValue(jawNumber, out barcode);
                    LiJuDictionaries.TryGetValue(jawNumber, out liJuValue);
                    var recordCsv = new ProductRecordCsv();
                    recordCsv.RecipeName = _currentRecipe.Name;
                    recordCsv.Shift = _shiftService.Current.GetDescription();
                    recordCsv.CreateTime = createTime;
                    recordCsv.Barcode = barcode;
                    recordCsv.JawNumber = jawNumber;
                    recordCsv.LijuValue = liJuValue;
                    recordCsv.BarcodeQuality = trayPointStatus == TrayPointStatus.OK || trayPointStatus == TrayPointStatus.CompletedOK ? "OK" : "NG";
                    recordCsv.RecheckQuality = trayPointStatus == TrayPointStatus.CompletedOK ? "OK" : "NG";
                    recordCsv.Quality = trayPointStatus == TrayPointStatus.CompletedOK ? "OK" : "NG";
                    SaveDataCsv(recordCsv, filePath);
                }
            }
        }
        public void SaveDataCsv(ProductRecordCsv productRecordCsv, string filePath)
        {
            try
            {
                try
                {
                    SaveCsvDataT(filePath, productRecordCsv);
                }
                catch
                {
                    OnBuildSaveCsvPath((p) => SaveCsvDataT(p, productRecordCsv), filePath);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"存储生产记录CSV数据文件异常{ex.Message}");
            }
        }
        public void SaveDataCsv(CalcTimeOption calcOption)
        {
            try
            {
                var option = _optionRepository.Get<DataStorageOption>();
                if (option.IsSaveCSV == false) return;
                var recordYield = new YieldRecordCsv();
                recordYield.RecipeName = _currentRecipe.Name;
                recordYield.Shift = _shiftService.Current.GetDescription();
                recordYield.CreateTime = DateTime.Now;
                recordYield.SumTotal = calcOption.Sum;
                recordYield.SumOK = calcOption.OK;
                recordYield.SumNG = calcOption.NG;
                recordYield.SumYield = calcOption.Sum != 0 ? 1.000 * calcOption.OK / calcOption.Sum : 0;
                recordYield.CT = calcOption.CurrentCT;
                recordYield.UPU = calcOption.CurrentUPH;
                var createTime = recordYield.CreateTime;
                if (recordYield.Shift == "晚班")
                    createTime = createTime.AddHours(-12);
                var dateStr = createTime.ToString("yyyy-MM-dd");
                string csvPath = Path.Combine(option.CSVPath, dateStr);
                EnsureExist(csvPath);
                var filePath = Path.Combine(csvPath, $"{dateStr}-产品良率.csv");
                try
                {
                    SaveCsvDataT(filePath, recordYield);
                }
                catch
                {
                    OnBuildSaveCsvPath((p) => SaveCsvDataT(p, recordYield), filePath);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"存储生产良率CSV数据文件异常{ex.Message}");
            }
        }
        void SaveCsvDataT<T>(string filePath, T csvData) where T : class
        {
            bool isNewCreateFile = false;
            if (!File.Exists(filePath))
                isNewCreateFile = true;
            using (FileStream fileStream = new FileStream(filePath, FileMode.Append, FileAccess.Write))
            {
                using (StreamWriter streamWriter = new StreamWriter(fileStream, Encoding.GetEncoding("GB2312")))
                {
                    using (var csvWriter = new CsvWriter(streamWriter, CultureInfo.CurrentUICulture))
                    {
                        if (isNewCreateFile)
                        {
                            csvWriter.WriteHeader<T>();
                            csvWriter.NextRecord();
                            csvWriter.Flush();
                            streamWriter.Flush();
                        }
                        csvWriter.WriteRecord(csvData);
                        csvWriter.NextRecord();
                        csvWriter.Flush();
                        streamWriter.Flush();
                    }
                }
            }
        }
        void EnsureExist(string path)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }
        void OnBuildSaveCsvPath(Action<string> action, string filePath)
        {
            _logger.LogError($"存储CSV数据文件已被打开");
            int i = 1;
            string tempFilePath = filePath;
            while (true)
            {
                tempFilePath = filePath.Replace(".csv", $"运行时别打开 ({i}).csv");
                try
                {
                    action?.Invoke(tempFilePath);
                    break;
                }
                catch
                {
                    i++;
                }
                if (i > 100)
                {
                    break;
                }
            }
        }

    }
}
public class YieldRecordCsv
{
    [Name("配方名称")]
    public string RecipeName { get; set; }
    [Name("班次")]
    public string Shift { get; set; }
    [Name("创建时间")]
    public DateTime CreateTime { get; set; }
    [Name("投入总数")]
    public int SumTotal { get; set; }
    [Name("OK总数")]
    public int SumOK { get; set; }
    [Name("NG总数")]
    public int SumNG { get; set; }
    [Name("总数良率")]
    public double SumYield { get; set; }
    [Name("CT")]
    public double CT { get; set; }
    [Name("UPH")]
    public double UPU { get; set; }
}
public class ProductRecordCsv
{
    [Name("配方名称")]
    public string RecipeName { get; set; }
    [Name("班次")]
    public string Shift { get; set; }
    [Name("创建时间")]
    public DateTime CreateTime { get; set; }
    [Name("产品条码")]
    public string Barcode { get; set; }
    [Name("夹爪序号")]
    public int JawNumber { get; set; }
    [Name("力矩值")]
    public double LijuValue { get; set; }
    [Name("读码结果")]
    public string BarcodeQuality { get; set; }
    [Name("复检结果")]
    public string RecheckQuality { get; set; }
    [Name("总结果")]
    public string Quality { get; set; }
}
